package sample.tree.node.expr;

import java.util.*;
import sample.tree.node.Node;
import sample.tree.Context;
import sample.tree.visitor.ASTPrinter;
import sample.tree.visitor.Visitor;
import sample.tree.visitor.VoidVisitor;
import static sample.tree.util.Util.*;
import sample.tree.node.expr.Expr;

public final class Const extends Expr {

	private final int value;
	private final int hashCode;  // cache

	public static Expr get(
			final Context context,
			final int value)
	{
		return context.intern(
			new Const(
					value));
	}

	private Const(
			final int value)
	{
		this.value = value;
		this.hashCode = hashCodeImpl();  // cache
	}

	public int getValue() {
		return value;
	}

	@Override
	public void visit(final VoidVisitor v) {
		v.inConst(this);
	}

	@Override
	public <TExpr>
	TExpr visit(
		final Visitor<TExpr> v)
	{
		return v.inConst(this);
	}

	@Override
	public boolean equals(final Object rhs) {
		if(this == rhs)
			return true;
		if(rhs instanceof Const)
			return equalsImpl((Const)rhs);
		return false;
	}

	private boolean equalsImpl(
			final Const rhs)
	{
		return eq(value, rhs.value);
	}

	@Override
	public int hashCode() {
		return hashCode;
	}

	private int hashCodeImpl() {
		int hash = 17;
		hash += hash(value);
		return hash;
	}

	@Override
	protected int compareToImpl(
			final Expr rhs)
	{
		return compareToImpl((Const)rhs);
	}

	private int compareToImpl(
			final Const rhs)
	{
		int cmp;
		cmp = cmp(value, rhs.value);
		if(cmp != EQ) return cmp;
		return EQ;
	}

	@Override
	public int ordinal() {
		return 4;
	}

	@Override
	public String toString() {
		return ASTPrinter.toString(this);
	}
}
